home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16.lha / Python-1.6 / Lib / Python1.6 / mailbox.py < prev    next >
Encoding:
Python Source  |  2000-04-04  |  9.5 KB  |  280 lines

  1. #! /usr/bin/env python
  2.  
  3. """Classes to handle Unix style, MMDF style, and MH style mailboxes."""
  4.  
  5.  
  6. import rfc822
  7. import os
  8.  
  9. class _Mailbox:
  10.  
  11.         def __init__(self, fp):
  12.                 self.fp = fp
  13.                 self.seekp = 0
  14.  
  15.         def seek(self, pos, whence=0):
  16.                 if whence==1:           # Relative to current position
  17.                         self.pos = self.pos + pos
  18.                 if whence==2:           # Relative to file's end
  19.                         self.pos = self.stop + pos
  20.                 else:                   # Default - absolute position
  21.                         self.pos = self.start + pos
  22.  
  23.         def next(self):
  24.                 while 1:
  25.                         self.fp.seek(self.seekp)
  26.                         try:
  27.                                 self._search_start()
  28.                         except EOFError:
  29.                                 self.seekp = self.fp.tell()
  30.                                 return None
  31.                         start = self.fp.tell()
  32.                         self._search_end()
  33.                         self.seekp = stop = self.fp.tell()
  34.                         if start <> stop:
  35.                                 break
  36.                 return rfc822.Message(_Subfile(self.fp, start, stop))
  37.  
  38. class _Subfile:
  39.  
  40.         def __init__(self, fp, start, stop):
  41.                 self.fp = fp
  42.                 self.start = start
  43.                 self.stop = stop
  44.                 self.pos = self.start
  45.  
  46.         def read(self, length = None):
  47.                 if self.pos >= self.stop:
  48.                         return ''
  49.                 remaining = self.stop - self.pos
  50.                 if length is None or length < 0:
  51.                         length = remaining
  52.                 elif length > remaining:
  53.                         length = remaining
  54.                 self.fp.seek(self.pos)
  55.                 data = self.fp.read(length)
  56.                 self.pos = self.fp.tell()
  57.                 return data
  58.  
  59.         def readline(self, length = None):
  60.                 if self.pos >= self.stop:
  61.                         return ''
  62.                 if length is None:
  63.                         length = self.stop - self.pos
  64.                 self.fp.seek(self.pos)
  65.                 data = self.fp.readline(length)
  66.                 self.pos = self.fp.tell()
  67.                 return data
  68.  
  69.         def readlines(self, sizehint = -1):
  70.                 lines = []
  71.                 while 1:
  72.                         line = self.readline()
  73.                         if not line:
  74.                                 break
  75.                         lines.append(line)
  76.                         if sizehint >= 0:
  77.                                 sizehint = sizehint - len(line)
  78.                                 if sizehint <= 0:
  79.                                         break
  80.                 return lines
  81.  
  82.         def tell(self):
  83.                 return self.pos - self.start
  84.  
  85.         def seek(self, pos, whence=0):
  86.                 if whence == 0:
  87.                         self.pos = self.start + pos
  88.                 elif whence == 1:
  89.                         self.pos = self.pos + pos
  90.                 elif whence == 2:
  91.                         self.pos = self.stop + pos
  92.  
  93.         def close(self):
  94.                 del self.fp
  95.  
  96. class UnixMailbox(_Mailbox):
  97.  
  98.         def _search_start(self):
  99.                 while 1:
  100.             pos = self.fp.tell()
  101.                         line = self.fp.readline()
  102.                         if not line:
  103.                                 raise EOFError
  104.                         if line[:5] == 'From ' and self._isrealfromline(line):
  105.                 self.fp.seek(pos)
  106.                                 return
  107.  
  108.         def _search_end(self):
  109.         self.fp.readline()    # Throw away header line
  110.                 while 1:
  111.                         pos = self.fp.tell()
  112.                         line = self.fp.readline()
  113.                         if not line:
  114.                                 return
  115.                         if line[:5] == 'From ' and self._isrealfromline(line):
  116.                                 self.fp.seek(pos)
  117.                                 return
  118.  
  119.         # An overridable mechanism to test for From-line-ness.
  120.         # You can either specify a different regular expression
  121.         # or define a whole new _isrealfromline() method.
  122.         # Note that this only gets called for lines starting with
  123.         # the 5 characters "From ".
  124.  
  125.         _fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \
  126.                            r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$"
  127.         _regexp = None
  128.  
  129.         def _isrealfromline(self, line):
  130.                 if not self._regexp:
  131.                         import re
  132.                         self._regexp = re.compile(self._fromlinepattern)
  133.                 return self._regexp.match(line)
  134.  
  135. class MmdfMailbox(_Mailbox):
  136.  
  137.         def _search_start(self):
  138.                 while 1:
  139.                         line = self.fp.readline()
  140.                         if not line:
  141.                                 raise EOFError
  142.                         if line[:5] == '\001\001\001\001\n':
  143.                                 return
  144.  
  145.         def _search_end(self):
  146.                 while 1:
  147.                         pos = self.fp.tell()
  148.                         line = self.fp.readline()
  149.                         if not line:
  150.                                 return
  151.                         if line == '\001\001\001\001\n':
  152.                                 self.fp.seek(pos)
  153.                                 return
  154.  
  155. class MHMailbox:
  156.  
  157.         def __init__(self, dirname):
  158.                 import re
  159.                 pat = re.compile('^[0-9][0-9]*$')
  160.                 self.dirname = dirname
  161.                 files = os.listdir(self.dirname)
  162.                 self.boxes = []
  163.                 for f in files:
  164.                         if pat.match(f):
  165.                                 self.boxes.append(f)
  166.  
  167.         def next(self):
  168.                 if not self.boxes:
  169.                         return None
  170.                 fn = self.boxes[0]
  171.                 del self.boxes[0]
  172.                 fp = open(os.path.join(self.dirname, fn))
  173.                 return rfc822.Message(fp)
  174.  
  175. class Maildir:
  176.  
  177.         # Qmail directory mailbox
  178.  
  179.         def __init__(self, dirname):
  180.                 import string
  181.                 self.dirname = dirname
  182.                 self.boxes = []
  183.  
  184.                 # check for new mail
  185.                 newdir = os.path.join(self.dirname, 'new')
  186.                 for file in os.listdir(newdir):
  187.                         if len(string.split(file, '.')) > 2:
  188.                                 self.boxes.append(os.path.join(newdir, file))
  189.  
  190.                 # Now check for current mail in this maildir
  191.                 curdir = os.path.join(self.dirname, 'cur')
  192.                 for file in os.listdir(curdir):
  193.                         if len(string.split(file, '.')) > 2:
  194.                                 self.boxes.append(os.path.join(curdir, file))
  195.  
  196.         def next(self):
  197.                 if not self.boxes:
  198.                         return None
  199.                 fn = self.boxes[0]
  200.                 del self.boxes[0]
  201.                 fp = open(os.path.join(self.dirname, fn))
  202.                 return rfc822.Message(fp)
  203.  
  204. class BabylMailbox(_Mailbox):
  205.  
  206.         def _search_start(self):
  207.                 while 1:
  208.                         line = self.fp.readline()
  209.                         if not line:
  210.                                 raise EOFError
  211.                         if line == '*** EOOH ***\n':
  212.                                 return
  213.  
  214.         def _search_end(self):
  215.                 while 1:
  216.                         pos = self.fp.tell()
  217.                         line = self.fp.readline()
  218.                         if not line:
  219.                                 return
  220.                         if line == '\037\014\n':
  221.                                 self.fp.seek(pos)
  222.                                 return
  223.  
  224.  
  225. def _test():
  226.         import time
  227.         import sys
  228.         import string
  229.         import os
  230.  
  231.         args = sys.argv[1:]
  232.         if not args:
  233.                 for key in 'MAILDIR', 'MAIL', 'LOGNAME', 'USER':
  234.                         if os.environ.has_key(key):
  235.                                 mbox = os.environ[key]
  236.                                 break
  237.                 else:
  238.                         print "$MAIL, $LOGNAME nor $USER set -- who are you?"
  239.                         return
  240.         else:
  241.                 mbox = args[0]
  242.         if mbox[:1] == '+':
  243.                 mbox = os.environ['HOME'] + '/Mail/' + mbox[1:]
  244.         elif not '/' in mbox:
  245.                 mbox = '/usr/mail/' + mbox
  246.         if os.path.isdir(mbox):
  247.                 if os.path.isdir(os.path.join(mbox, 'cur')):
  248.                         mb = Maildir(mbox)
  249.                 else:
  250.                         mb = MHMailbox(mbox)
  251.         else:
  252.                 fp = open(mbox, 'r')
  253.                 mb = UnixMailbox(fp)
  254.         
  255.         msgs = []
  256.         while 1:
  257.                 msg = mb.next()
  258.                 if msg is None:
  259.                         break
  260.                 msgs.append(msg)
  261.                 if len(args) <= 1:
  262.                         msg.fp = None
  263.         if len(args) > 1:
  264.                 num = string.atoi(args[1])
  265.                 print 'Message %d body:'%num
  266.                 msg = msgs[num-1]
  267.                 msg.rewindbody()
  268.                 sys.stdout.write(msg.fp.read())
  269.         else:
  270.                 print 'Mailbox',mbox,'has',len(msgs),'messages:'
  271.                 for msg in msgs:
  272.                         f = msg.getheader('from') or ""
  273.                         s = msg.getheader('subject') or ""
  274.                         d = msg.getheader('date') or ""
  275.                         print '%20.20s   %18.18s   %-30.30s'%(f, d[5:], s)
  276.  
  277.  
  278. if __name__ == '__main__':
  279.         _test()
  280.